/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2010 University College London 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Joao Taveira Araujo <j.araujo@ucl.ac.uk>
 */

#include "ipv4-react-table-entry.h"
#include "ipv4-react-routing.h"
#include "ns3/assert.h"
#include "ns3/simulator.h"
#include "ns3/trace-source-accessor.h"

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (Ipv4ReactTableEntry);

TypeId 
Ipv4ReactTableEntry::GetTypeId (void) 
{
   static TypeId tid = TypeId ("ns3::Ipv4ReactRouting::Ipv4ReactTableEntry")
    .SetParent<Ipv4ReactRouting> ()
    .AddConstructor<Ipv4ReactTableEntry> ()
    .AddAttribute ("AlphaLoss", "Weight for weighted exponential average of loss.",
                   DoubleValue (0.2),
                   MakeDoubleAccessor (&Ipv4ReactTableEntry::m_alpha),
                   MakeDoubleChecker<double> ())
    ;
  return tid;
}

Ipv4ReactTableEntry::Ipv4ReactTableEntry ()
{
}
  
Ipv4ReactTableEntry::Ipv4ReactTableEntry (Ipv4Address network,
                      Ipv4Mask networkMask,
                      uint32_t interface)
  : m_dest (network),
    m_destNetworkMask (networkMask),
    m_interface (interface),
    m_wghtTxmit(0),
    m_wghtRexmit(0),
    m_instTxmit(0),
    m_instRexmit(0),
    m_tokenCounter(0)
{
  Clear();  
}

Ipv4Address 
Ipv4ReactTableEntry::GetDestNetwork (void) const
{
  return m_dest;
}

Ipv4Mask 
Ipv4ReactTableEntry::GetDestNetworkMask (void) const
{
  return m_destNetworkMask;
}

uint32_t
Ipv4ReactTableEntry::GetInterface (void) const
{
  return m_interface;
}
 

/* PREF */

double 
Ipv4ReactTableEntry::IncrementTokenCount ()
{
  m_tokenCounter = m_tokenCounter + GetFlowSplit();
  return m_tokenCounter;
}

void 
Ipv4ReactTableEntry::DecrementTokenCount ()
{
  m_tokenCounter--;
}

void 
Ipv4ReactTableEntry::SetFlowSplit (double newFlowSplit) 
{
  m_flowSplit = newFlowSplit;
}

double 
Ipv4ReactTableEntry::GetFlowSplit () const
{
  return m_flowSplit;
}

double
Ipv4ReactTableEntry::GetWghtTheta () 
{
  return m_wghtTheta;
}

double
Ipv4ReactTableEntry::GetInstTheta () 
{
  return m_instTheta;
}

/* LEX */

void
Ipv4ReactTableEntry::Timestep ()
{
  m_instTxmit   = m_tmpTxmit;
  m_instRexmit  = m_count[LE];

  //clear temp variables for next timestep;
  Clear();

  m_wghtTxmit   = (1.0-m_alpha)*m_wghtTxmit + m_alpha*m_instTxmit;
  m_wghtRexmit  = (1.0-m_alpha)*m_wghtRexmit + m_alpha*m_instRexmit;

  //calculate theta
  m_instTheta   = m_instTxmit * m_instTxmit;
  if (m_instRexmit)
    m_instTheta /= m_instRexmit;
  
  m_wghtTheta   = m_wghtTxmit * m_wghtTxmit;
  if (m_wghtRexmit)
    m_wghtTheta /= m_wghtRexmit;
}

void
Ipv4ReactTableEntry::Clear ()
{
  for (int i = 0; i < MAX_CODEPOINT; i++)
    m_count[i] = 0;
  m_tmpTxmit = 0;
}

void 
Ipv4ReactTableEntry::CountLex (int codepoint, const unsigned int value)
{
  NS_ASSERT ( codepoint < MAX_CODEPOINT );
  m_count[codepoint] += value;
  m_tmpTxmit += value;
}

double 
Ipv4ReactTableEntry::GetWghtLoss () const
{
  if (m_wghtTxmit)
    return m_wghtRexmit/m_wghtTxmit;
  return 0;
}

double
Ipv4ReactTableEntry::GetInstLoss () const
{
  if (m_instTxmit)
    return m_instRexmit/m_instTxmit;
  return 0;
}

double
Ipv4ReactTableEntry::GetWghtTxmit () 
{
  return m_wghtTxmit;
}

double
Ipv4ReactTableEntry::GetInstTxmit () 
{
  return m_instTxmit;
}

double
Ipv4ReactTableEntry::GetWghtRexmit () 
{
  return m_wghtRexmit;
}

double
Ipv4ReactTableEntry::GetInstRexmit () 
{
  return m_instRexmit;
}

std::ostream& operator<< (std::ostream& os, Ipv4ReactTableEntry const& route)
{
  os << "network=" << route.GetDestNetwork () <<
    ", mask=" << route.GetDestNetworkMask () <<
    ",out=" << route.GetInterface () <<
    ",flowSplit=" << route.GetFlowSplit () <<
    ",loss=" << route.GetWghtLoss ();
  return os;
}

} //namespace ns3
